package com.metaverse.backend.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.utils.StringUtils;
import com.metaverse.backend.config.RedisCacheKey;
import com.metaverse.backend.domain.LiveComment;
import com.metaverse.backend.domain.LiveGift;
import com.metaverse.backend.domain.LiveLike;
import com.metaverse.backend.douyin.*;
import com.metaverse.backend.dto.RoomProgressUpdateDTO;
import com.metaverse.backend.enums.GiftTypeEnum;
import com.metaverse.backend.enums.MsgTypeEnum;
import com.metaverse.backend.exception.BusinessException;

import com.metaverse.backend.service.RoomDataManage;
import com.metaverse.backend.service.RoundHelper;
import com.metaverse.backend.task.Constant;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;


/**
 * 房间数据管理
 */
@Service
@Slf4j
@AllArgsConstructor
public class RoomDataManageV2Impl implements RoomDataManage {


    private RedisTemplate<String, Object> redisTemplate;

//    private RocketMQTemplate rocketMQTemplate;

    private static final Random random = new Random();
    private RoundHelper roundHelper;
    /**
     * 捕获对方的指令判断模式
     */
    public static final Pattern CAPTURE_PATTERN = Pattern.compile("^\\s*@?(.+)\\s*抓\\s*$|^\\s*抓\\s*@?(.+)\\s*$");


    @Override
    public boolean supportVersion(String gameVersion) {
        if (StringUtils.isNotEmpty(gameVersion) && gameVersion.compareTo(LIMIT_VERSION_V1) > 0) {
            return true;
        }

        return false;
    }


    /**
     * 接收抖音推送数据按照房间丢到redis
     *
     * @param roomId
     * @param reqData
     */
    @Override
    public void pushMsg(String roomId, String reqData, String msg_type) {
        String roundId = roundHelper.currentRoundId(roomId);

        if (StringUtils.isEmpty(roundId)) {
            //一局结束 新局未开启 数据不做保存
            log.warn("游戏新局未开启,忽略内容：" + reqData);
            return;
        }

        RoomDataDTO roomDataDTO = this.getRoomDataDTO(roomId, roundId);
        if (roomDataDTO == null) {
            //一局结束 新局未开启 数据不做保存
            log.warn("roomDataDTO,为空：" + roomDataDTO);
            return;
        }

        if (MsgTypeEnum.LIVE_COMMENT.getDescription().equals(msg_type)) {
            //解析评论数据
            List<LiveComment> dataList = LIVE_COMMENT(reqData, roomId, roundId, roomDataDTO);
//            rocketMQTemplate.asyncSend(MqConstant.ROOM_DATA_LIVE_COMMENT, dataList, new RoomDataSendCallback());
            Constant.LiveCommentlist.addAll(dataList);
        } else if (MsgTypeEnum.LIVE_GIFT.getDescription().equals(msg_type)) {
            List<LiveGift> dataList = LIVE_GIFT(reqData, roomId, roundId, roomDataDTO);
//            rocketMQTemplate.asyncSend(MqConstant.ROOM_DATA_LIVE_GIFT, dataList, new RoomDataSendCallback());
            Constant.LiveGiftlist.addAll(dataList);
        } else if (MsgTypeEnum.LIVE_LIKE.getDescription().equals(msg_type)) {
            List<LiveLike> dataList = LIVE_LIKE(reqData, roomId, roundId, roomDataDTO);
            Constant.LiveLikelist.addAll(dataList);
//            rocketMQTemplate.asyncSend(MqConstant.ROOM_DATA_LIVE_LIKE, dataList, new RoomDataSendCallback());
        } else {
            log.error("推送未知数据，房间{},类型{},reqData{}", roomId, msg_type, reqData);
            return;
        }
        String roomDataKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_PROGRESS, roomId, roundId);

        redisTemplate.opsForValue().set(roomDataKey, roomDataDTO, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);
    }


    /**
     * 创建玩家信息 并初始化数据
     *
     * @param item
     * @return
     */
    private PlayerDataDTO createPlayerData(LiveComment item, Integer joinLocation) {
        PlayerDataDTO playerDataDto = new PlayerDataDTO();
        playerDataDto.setAvatar_url(item.getAvatar_url());
        playerDataDto.setNickname(item.getNickname());
        playerDataDto.setSec_openid(item.getSec_openid());
        playerDataDto.setScore(10L);//加入送10积分
        playerDataDto.setLocation(joinLocation);
        //获取世界排名
        Long rank = redisTemplate.opsForZSet().reverseRank(RedisCacheKey.RANKING, item.getSec_openid());
        if (rank != null && rank >= 0) {
            playerDataDto.setWorldRank(Math.toIntExact(rank + 1));//世界排名
        } else {
            playerDataDto.setWorldRank(9999999);//世界排名
        }
        //查找连胜记录
        Double winStreak = redisTemplate.opsForZSet().score(RedisCacheKey.WINSTREAK, item.getSec_openid());
        playerDataDto.setWinningStreak(winStreak == null ? 0 : winStreak.intValue());
        return playerDataDto;
    }

    /**
     * 创建消息对象
     *
     * @param msgId
     * @param playerDataDTO
     * @return
     */
    private MsgDataDTO createMsgDto(String msgId, PlayerDataDTO playerDataDTO, GiftDTO giftDTO) {
        MsgDataDTO msgDataDTO = new MsgDataDTO();
        msgDataDTO.setMsgId(msgId);
        msgDataDTO.setSec_openid(playerDataDTO.getSec_openid());
        msgDataDTO.setAvatar_url(playerDataDTO.getAvatar_url());
        msgDataDTO.setNickname(playerDataDTO.getNickname());
        msgDataDTO.setScore(playerDataDTO.getScore());
        msgDataDTO.setLocation(playerDataDTO.getLocation());
        msgDataDTO.setWorldRank(playerDataDTO.getWorldRank());
        msgDataDTO.setGift_info(giftDTO);
        msgDataDTO.setCamp(getCamp(playerDataDTO.getLocation()));
        return msgDataDTO;
    }
    /**
     * 根据十二生肖阵营获取阵营名称
     */
    private String getCamp(Integer location) {
        if (location == null) {
            return "未知";
        }
        if (location == 0) {
            return "未知";
        }
        switch (location) {
            case 1:
                return "鼠";
            case 2:
                return "牛";
            case 3:
                return "虎";
            case 4:
                return "兔";
            case 5:
                return "龙";
            case 6:
                return "蛇";
            case 7:
                return "马";
            case 8:
                return "羊";
            case 9:
                return "猴";
            case 10:
                return "鸡";
            case 11:
                return "狗";
            case 12:
                return "猪";
            default:
                return "未知";
        }
    }

    /**
     * 获取礼物对象
     *
     * @param playerDataDTO
     * @param giftTypeEnum
     * @return
     */
    private GiftDTO createGiftDto(PlayerDataDTO playerDataDTO, GiftTypeEnum giftTypeEnum) {
        GiftDTO giftDTO = new GiftDTO();
        giftDTO.setName(giftTypeEnum.name());
        giftDTO.setSecGiftId(giftTypeEnum.getId());
        giftDTO.setInvalidTime(System.currentTimeMillis());

        //设置累计数量
        {
            List<GiftDTO> giftDtoList = playerDataDTO.getGift_map().get(giftTypeEnum.name());
            if (giftDtoList != null && giftDtoList.size() > 0) {
                GiftDTO lastGiftDto = giftDtoList.get(giftDtoList.size() - 1);
                giftDTO.setTotalNum(lastGiftDto.getTotalNum());
            }
        }

        return giftDTO;
    }


    /**
     * 解析评论数据
     *
     * @param roomId
     * @param roundId
     */
    private List<LiveComment> LIVE_COMMENT(String reqData, String roomId, String roundId, RoomDataDTO roomDataDTO) {
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);//后端备份的数据
        String dataListKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_LIST, roomId, roundId);//前端队列数据的KEY

        //评论数据列表
        List<LiveComment> dataList = new ArrayList<>();
        //玩家数据列表
        Map<String, PlayerDataDTO> changedPlayerDataMap = new HashMap<>();

        JSONArray arr = JSONObject.parseArray(reqData);
        Map<Object, Object> hashOps = redisTemplate.opsForHash().entries(dataMapKey);
        for (int i = 0; i < arr.size(); i++) {
            LiveComment item = arr.getJSONObject(i).toJavaObject(LiveComment.class);
            item.setRoomId(roomId);
            item.setRoundId(roundId);
            dataList.add(item);
            //根据redis获取玩家数据
            PlayerDataDTO playerDataDto = (PlayerDataDTO) hashOps.get(item.getSec_openid());
            changedPlayerDataMap.put(item.getSec_openid(), playerDataDto);
        }

        //根据评论数据设置玩家阵营
        for (LiveComment item : dataList) {
            //根据openid唯一获取玩家数据
            PlayerDataDTO playerDataDto = changedPlayerDataMap.get(item.getSec_openid());

            Integer joinLocation = null;
            //根据评论选择阵营
            joinLocation = getInteger(item, playerDataDto, joinLocation);
            if (joinLocation != null) {
                if (playerDataDto == null) {
                    //创建玩家数据
                    playerDataDto = createPlayerData(item, joinLocation);
                    changedPlayerDataMap.put(item.getSec_openid(), playerDataDto);
                    MsgDataDTO msgDataDTO = createMsgDto(item.getMsg_id(), playerDataDto, null);
                    changeNewToRedis(dataListKey, msgDataDTO);
                    roomDataDTO.setScorePool(roomDataDTO.getScorePool().add(BigDecimal.valueOf(playerDataDto.getScore())));
                }
//                else {
//                    Integer addedScore = GiftTypeEnum.ZERO.getScore();
//                    addedScore += BigDecimal.valueOf(addedScore).multiply(BigDecimal.valueOf(playerDataDto.getWinningStreak() / 1000D)).intValue();
//                    playerDataDto.setScore(playerDataDto.getScore() + addedScore);
//                    roomDataDTO.setScorePool(roomDataDTO.getScorePool().add(BigDecimal.valueOf(addedScore)));
//                    GiftDTO giftDTO = createGiftDto(playerDataDto, GiftTypeEnum.ZERO);
//                    Long invalidTime = System.currentTimeMillis() + (GiftTypeEnum.ZERO.getValidTime() + 2) * 1000L;
//                    giftDTO.setInvalidTime(invalidTime);
//                    giftDTO.setChangeNum(3);
//                    giftDTO.setTotalNum(giftDTO.getTotalNum() + giftDTO.getChangeNum());
//                    playerDataDto.cleanInvalidAndAdd(giftDTO);
//                    MsgDataDTO msgDataDTO = createMsgDto(item.getMsg_id(), playerDataDto, giftDTO);
//                    changeNewToRedis(dataListKey, msgDataDTO);
//                }
            }
        }
        //全部放入redis中
        changeAllToRedis(dataMapKey, changedPlayerDataMap.values());

        return dataList;
    }

    /**
     * 根据评论数据获取玩家数据
     *
     * @param item
     * @param playerDataDto
     * @param joinLocation
     * @return
     */
    private static Integer getInteger(LiveComment item, PlayerDataDTO playerDataDto, Integer joinLocation) {
        //判断加入是否是第一次加入和加入阵营
        if (playerDataDto == null && (item.getContent().equals("子") || item.getContent().equals("鼠")) || (item.getContent().equals("1"))) {
            joinLocation = 1;
        } else if (playerDataDto == null && (item.getContent().equals("丑") || item.getContent().equals("牛")) || (item.getContent().equals("2"))) {
            joinLocation = 2;
        } else if (playerDataDto != null && (item.getContent().equals("寅") || item.getContent().equals("虎")) || (item.getContent().equals("3"))) {
            joinLocation = 3;
        } else if (playerDataDto != null && (item.getContent().equals("卯") || item.getContent().equals("兔")) || (item.getContent().equals("4"))) {
            joinLocation = 4;
        } else if (playerDataDto != null && (item.getContent().equals("辰") || item.getContent().equals("龙")) || (item.getContent().equals("5"))) {
            joinLocation = 5;
        } else if (playerDataDto != null && (item.getContent().equals("巳") || item.getContent().equals("蛇")) || (item.getContent().equals("6"))) {
            joinLocation = 6;
        } else if (playerDataDto != null && (item.getContent().equals("午") || item.getContent().equals("马")) || (item.getContent().equals("7"))) {
            joinLocation = 7;
        } else if (playerDataDto != null && (item.getContent().equals("未") || item.getContent().equals("羊")) || (item.getContent().equals("8"))) {
            joinLocation = 8;
        } else if (playerDataDto != null && (item.getContent().equals("申") || item.getContent().equals("猴")) || (item.getContent().equals("9"))) {
            joinLocation = 9;
        } else if (playerDataDto != null && (item.getContent().equals("酉") || item.getContent().equals("鸡")) || (item.getContent().equals("10"))) {
            joinLocation = 10;
        } else if (playerDataDto != null && (item.getContent().equals("戌") || item.getContent().equals("狗")) || (item.getContent().equals("11"))) {
            joinLocation = 11;
        } else if (playerDataDto != null && (item.getContent().equals("亥") || item.getContent().equals("猪")) || (item.getContent().equals("12"))) {
            joinLocation = 12;
        }
        return joinLocation;
    }


    /**
     * 解析礼物数据
     *
     * @param reqData     请求数据
     * @param roomId      房间ID
     * @param roundId     轮次ID
     * @param roomDataDTO 房间数据DTO
     * @return 解析后的礼物列表
     */
    private List<LiveGift> LIVE_GIFT(String reqData, String roomId, String roundId, RoomDataDTO roomDataDTO) {
        if (reqData == null || reqData.isEmpty() || roomId == null || roomId.isEmpty() || roundId == null || roundId.isEmpty()) {
            throw new IllegalArgumentException("Invalid input parameters");
        }

        try {
            String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);
            String dataListKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_LIST, roomId, roundId);

            List<LiveGift> dataList = new ArrayList<>();
            Map<String, PlayerDataDTO> changedPlayerDataMap = new HashMap<>();

            JSONArray arr = JSONArray.parseArray(reqData);
            for (int i = 0; i < arr.size(); i++) {
                JSONObject jsonObject = arr.getJSONObject(i);
                LiveGift item = jsonObject.toJavaObject(LiveGift.class);
                item.setRoomId(roomId);
                item.setRoundId(roundId);
                dataList.add(item);

                String secOpenid = item.getSec_openid();
                if (secOpenid == null || secOpenid.isEmpty()) {
                    continue;
                }

                //获取唯一用户
                PlayerDataDTO playerDataDto = (PlayerDataDTO) redisTemplate.opsForHash().get(dataMapKey, secOpenid);
                if (playerDataDto == null) {
                    LiveComment jiaru = jsonObject.toJavaObject(LiveComment.class);
                    GiftTypeEnum giftTypeEnum = GiftTypeEnum.getType(item.getSec_gift_id());
                    //一个仙女棒随机加入
                    if (giftTypeEnum.getId().equals("n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=")) {
                        playerDataDto = createPlayerData(jiaru, random.nextInt(12) + 1);
                    }
                    //刷礼物是否随机加入一个阵营 降魔记的
//                    playerDataDto = createPlayerData(jiaru, random.nextInt(2) + 1);
                }
                changedPlayerDataMap.put(secOpenid, playerDataDto);
            }

            for (LiveGift item : dataList) {
                PlayerDataDTO playerDataDto = changedPlayerDataMap.get(item.getSec_openid());
                if (playerDataDto == null) {
                    continue;
                }

                GiftTypeEnum giftTypeEnum = GiftTypeEnum.getType(item.getSec_gift_id());
                if (giftTypeEnum == null) {
                    continue;
                }

                int addedScore = calculateAddedScore(giftTypeEnum, item, playerDataDto);
                playerDataDto.setScore((long) addedScore);
                roomDataDTO.setScorePool(roomDataDTO.getScorePool().add(BigDecimal.valueOf(addedScore)));

                GiftDTO giftDTO = createGiftDto(playerDataDto, giftTypeEnum);
                Long invalidTime = System.currentTimeMillis() + (giftTypeEnum.getValidTime() + 2) * 1000L;
                giftDTO.setInvalidTime(invalidTime);
                giftDTO.setChangeNum(item.getGift_num());
                giftDTO.setTotalNum(giftDTO.getTotalNum() + giftDTO.getChangeNum());

                playerDataDto.cleanInvalidAndAdd(giftDTO);

                MsgDataDTO msgDataDTO = createMsgDto(item.getMsg_id(), playerDataDto, giftDTO);
                changeNewToRedis(dataListKey, msgDataDTO);
            }

            changeAllToRedis(dataMapKey, changedPlayerDataMap.values());
            return dataList;
        } catch (Exception e) {
            // Log the exception and handle it appropriately
            throw new RuntimeException("Error processing live gift data", e);
        }
    }

    private int calculateAddedScore(GiftTypeEnum giftTypeEnum, LiveGift item, PlayerDataDTO playerDataDto) {
        int baseScore = giftTypeEnum.getScore() * item.getGift_num();
        BigDecimal bonusScore = BigDecimal.valueOf(baseScore)
                .multiply(BigDecimal.valueOf(playerDataDto.getWinningStreak() / 1000D));
        return baseScore + bonusScore.intValue();
    }


    /**
     * 解析点赞数据
     *
     * @param reqData
     * @param roomId
     * @param roundId
     * @return
     */
    private List<LiveLike> LIVE_LIKE(String reqData, String roomId, String roundId, RoomDataDTO roomDataDTO) {
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);//后端备份的数据
        String dataListKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_LIST, roomId, roundId);//前端队列数据的KEY

        List<LiveLike> dataList = new ArrayList<>();
        Map<String, PlayerDataDTO> changedPlayerDataMap = new HashMap<>();

        JSONArray arr = JSONObject.parseArray(reqData);
        for (int i = 0; i < arr.size(); i++) {
            LiveLike item = arr.getJSONObject(i).toJavaObject(LiveLike.class);
            item.setRoomId(roomId);
            item.setRoundId(roundId);

            PlayerDataDTO playerDataDto = (PlayerDataDTO) redisTemplate.opsForHash().get(dataMapKey, item.getSec_openid());
            if (playerDataDto == null) {
                continue;
//                //加入
//                LiveComment jiaru = arr.getJSONObject(i).toJavaObject(LiveComment.class);
//                playerDataDto = createPlayerData(jiaru, random.nextInt(2)+1);
            }
            dataList.add(item);
            changedPlayerDataMap.put(item.getSec_openid(), playerDataDto);

        }

        for (LiveLike item : dataList) {
            PlayerDataDTO playerDataDto = changedPlayerDataMap.get(item.getSec_openid());
            if (playerDataDto != null) {
//                Integer addedScore = GiftTypeEnum.ZERO.getScore() * item.getLike_num();
//                addedScore += BigDecimal.valueOf(addedScore).multiply(BigDecimal.valueOf(playerDataDto.getWinningStreak() / 1000D)).intValue();
//                roomDataDTO.setScorePool(roomDataDTO.getScorePool().add(BigDecimal.valueOf(addedScore)));
//                playerDataDto.setScore(playerDataDto.getScore() + addedScore);

                GiftDTO giftDTO = createGiftDto(playerDataDto, GiftTypeEnum.ZERO);

                Long invalidTime = System.currentTimeMillis() + (GiftTypeEnum.ZERO.getValidTime() + 2) * 1000L;
                giftDTO.setInvalidTime(invalidTime);
                giftDTO.setChangeNum(item.getLike_num());
                giftDTO.setTotalNum(giftDTO.getTotalNum() + giftDTO.getChangeNum());
                playerDataDto.cleanInvalidAndAdd(giftDTO);

                MsgDataDTO msgDataDTO = createMsgDto(item.getMsg_id(), playerDataDto, giftDTO);
                changeNewToRedis(dataListKey, msgDataDTO);

            }

        }

        changeAllToRedis(dataMapKey, changedPlayerDataMap.values());


        return dataList;
    }

    /**
     * 把解析的数据丢到redis
     */
    private void changeAllToRedis(String dataMapKey, Collection<PlayerDataDTO> changeList) {
        changeList.forEach(item -> {
            if (item != null) {
                String secOpenId = item.getSec_openid();
                redisTemplate.opsForHash().put(dataMapKey, secOpenId, item);
            }
        });

        redisTemplate.expire(dataMapKey, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);

    }

    /**
     * 添加队列数据
     *
     * @param dataListKey
     * @param msgDataDTO
     */
    private void changeNewToRedis(String dataListKey, MsgDataDTO msgDataDTO) {
        redisTemplate.opsForList().leftPush(dataListKey, msgDataDTO);
        redisTemplate.expire(dataListKey, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);
    }

    /**
     * 获取房间数据
     *
     * @param roomId
     * @return
     */
    @Override
    @Nullable
    public RoomDataDTO getRoomDataDTO(String roomId, String roundId) {

        String roomDataKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_PROGRESS, roomId, roundId);
        RoomDataDTO roomDataDTO = (RoomDataDTO) redisTemplate.opsForValue().get(roomDataKey);
        if (roomDataDTO != null) {
            roomDataDTO.setTimestamp(System.currentTimeMillis());
        }


        return roomDataDTO;
    }


    /**
     * 更新进度
     *
     * @param roomId
     * @return
     */
    @Override
    public RoomDataDTO updateRoomDataProgress(String roomId, List<RoomProgressUpdateDTO> roomProgressUpdateDTOList) {

        String roundId = roundHelper.currentRoundId(roomId);
        RoomDataDTO roomDataDTO = this.getRoomDataDTO(roomId, roundId);
        if (roomDataDTO == null) {
            roomDataDTO = new RoomDataDTO();
            roomDataDTO.setRoomId(roomId);
            roomDataDTO.setRoundId(roundId);
            roomDataDTO.setStartTime(System.currentTimeMillis());
            Object difen = redisTemplate.opsForValue().get(RedisCacheKey.DIFEN + roomId);
            if (difen != null) {
                try {
                    roomDataDTO.setScorePool(BigDecimal.valueOf(Long.parseLong(difen.toString())));
                } catch (Exception e) {

                }

            }
        }
        roomDataDTO.setProgress(roomProgressUpdateDTOList);

        String roomDataKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_PROGRESS, roomId, roundId);

        redisTemplate.opsForValue().set(roomDataKey, roomDataDTO, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);
        return roomDataDTO;
    }


    /**
     * 结束游戏TODO游戏判定改变场上只有一个阵营
     *
     * @param roomId
     * @return
     */
    @Override
    public RoomDataDTO endGame(String roomId) {

        String roundId = roundHelper.currentRoundId(roomId);

        RoomDataDTO roomDataDTO = this.getRoomDataDTO(roomId, roundId);


        if (roomDataDTO == null || roomDataDTO.isGameEnd()) {
            throw new BusinessException("游戏已结束，请重新开始");
        }
        List<RoomProgressUpdateDTO> progress = roomDataDTO.getProgress();
        for (RoomProgressUpdateDTO dto : progress) {
            if (!dto.getIsDestroy()) {
                roomDataDTO.setVictoryLocation(dto.getLocation());
            }
        }

//        if (BigDecimal.ZERO.compareTo(roomDataDTO.getProgress()) < 0) {

//        } else {
//            roomDataDTO.setVictoryLocation(2);
//        }
        roomDataDTO.setGameEnd(true);
        roomDataDTO.setEndTime(System.currentTimeMillis());

        String roomDataKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_PROGRESS, roomId, roundId);
        redisTemplate.opsForValue().set(roomDataKey, roomDataDTO, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);


        Integer difen = roomDataDTO.getScorePool().multiply(BigDecimal.valueOf(0.2)).intValue();
        redisTemplate.opsForValue().set(RedisCacheKey.DIFEN + roomId, difen, REDIS_CACHE_TIMEOUT, TimeUnit.SECONDS);
        return roomDataDTO;

    }


    /**
     * 前端获取抖音推送数据
     */
    @Override
    public void appendChangedMsgData(RoomDataDTO roomDataDTO) {
        String roomId = roomDataDTO.getRoomId();
        List<MsgDataDTO> msgDataDTOList = new ArrayList<>();
        String roundId = roundHelper.currentRoundId(roomId);
        if (StringUtils.isEmpty(roundId)) {
            //一局结束 新局未开启 数据不做保存
            return;
        }


        String roomDataListKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA_LIST, roomId, roundId);
        MsgDataDTO value;
        while ((value = (MsgDataDTO) redisTemplate.opsForList().rightPop(roomDataListKey)) != null) {
            msgDataDTOList.add(value);
        }

        roomDataDTO.setMsgDataList(msgDataDTOList);

    }


    /**
     * 获取直播本局间所有数据  断线重连用
     *
     * @param roomId 房间id
     */
    @Override
    public List<PlayerDataDTO> getAllPlayerData(String roomId) {
        String roundId = roundHelper.currentRoundId(roomId);
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);//后端备份的数据
        List<Object> list = redisTemplate.opsForHash().values(dataMapKey);
        List<PlayerDataDTO> allData = new ArrayList<>();
        list.forEach(e -> allData.add((PlayerDataDTO) e));
        return allData;
    }


    /**
     * 获取本局排行数据
     *
     * @param roomId      房间id
     * @param roomDataDTO 房间数据传输对象
     * @return 排名前100的玩家数据列表
     */
    @Override
    public List<PlayerDataDTO> sortAndGetRankList(String roomId, RoomDataDTO roomDataDTO) {
        // 获取房间内所有玩家的数据
        List<PlayerDataDTO> list = this.getAllPlayerData(roomId);
        // 根据分数对玩家列表进行降序排序
        list.sort(Comparator.comparing(PlayerDataDTO::getScore).reversed());
        // 定义奖金分配比例
        BigDecimal firstRatio = new BigDecimal("0.4");
        BigDecimal twoRatio = new BigDecimal("0.30");
        BigDecimal threeRatio = new BigDecimal("0.15");
        BigDecimal fourRatio = new BigDecimal("0.1");
        BigDecimal fiveRatio = new BigDecimal("0.05");
        List<BigDecimal> ratios = Arrays.asList(firstRatio, twoRatio, threeRatio, fourRatio, fiveRatio);
        int streakPool = 0;

        // 筛选获胜玩家
        List<PlayerDataDTO> winList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            PlayerDataDTO item = list.get(i);
            if (roomDataDTO.getVictoryLocation() == item.getLocation()) {
                winList.add(item);
            }
        }
        //筛选败方玩家
        List<PlayerDataDTO> loseList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            PlayerDataDTO item = list.get(i);
            if (roomDataDTO.getVictoryLocation() != item.getLocation()) {
                loseList.add(item);
            }
        }
        //将败方的连胜放入连胜池中
        for (PlayerDataDTO playerDataDTO : loseList) {
            if (playerDataDTO.getScore() < 50000) {
                streakPool += playerDataDTO.getWinningStreak();
            }
        }
        // 为获胜玩家分配奖金
        for (int i = 0; i < winList.size() && i < ratios.size(); i++) {
            // 获取获胜玩家的数据显示对象
            PlayerDataDTO itemDto = winList.get(i);
            // 获取当前玩家的分配比例
            BigDecimal curRatio = ratios.get(i);
            // 计算当前奖池的百分之80做为奖金
            BigDecimal addedScore = roomDataDTO.getScorePool().multiply(new BigDecimal("0.8")).multiply(curRatio).setScale(0, RoundingMode.UP);
            // 更新玩家的总分数
            itemDto.setScore(itemDto.getScore() + addedScore.intValue());
            // 设置玩家本次分配得到的分数
            itemDto.setAllotScore(addedScore.intValue());
        }

        int winnerCount = 0;
        // 更新玩家排名和胜利状态
        for (int i = 0; i < list.size(); i++) {
            PlayerDataDTO item = list.get(i);
            item.setRank(i + 1);
            item.setPreWorldRank(item.getWorldRank());
            // 添加成绩到世界排名中
            redisTemplate.opsForZSet().incrementScore(RedisCacheKey.RANKING, item.getSec_openid(), item.getScore());
            // 判断当前玩家是否胜利，如果是，则更新胜利状态和胜利次数，并添加胜利次数到世界排名中
            if (roomDataDTO.getVictoryLocation() == item.getLocation()) {
                item.setVictory(true);
                //可瓜分的积分
                if (item.getScore() > 10000 && winnerCount < 5) {
                    //按照比例瓜分ratios
                    BigDecimal bigDecimal = new BigDecimal(streakPool);
                    int winNum = bigDecimal.multiply(ratios.get(winnerCount++)).setScale(0, RoundingMode.UP).intValue();
                    redisTemplate.opsForZSet().incrementScore(RedisCacheKey.WINSTREAK, item.getSec_openid(), winNum);
                    item.setWinningStreak(item.getWinningStreak() + winNum);
                    item.setCurrentWinningStreak(winNum);
                } else {
                    //普通玩家瓜分连胜
                    redisTemplate.opsForZSet().incrementScore(RedisCacheKey.WINSTREAK, item.getSec_openid(), 1);
                    item.setWinningStreak(item.getWinningStreak() + 1);
                    item.setCurrentWinningStreak(1);
                }
            } else {//
                //失败玩家失去连胜全部连胜，大哥除外
                if (item.getScore() < 50000) {
                    redisTemplate.opsForZSet().incrementScore(RedisCacheKey.WINSTREAK, item.getSec_openid(), -item.getWinningStreak());
                    item.setWinningStreak(0);
                    item.setCurrentWinningStreak(0);
                }
            }
        }

        // 获取当前轮次id
        String roundId = roundHelper.currentRoundId(roomId);
        // 获取Redis中存储房间数据的键
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);
        // 更新玩家的世界排名和总贡献值，并保存到Redis缓存中
        for (int i = 0; i < list.size(); i++) {
            PlayerDataDTO item = list.get(i);
            Long rank = redisTemplate.opsForZSet().reverseRank(RedisCacheKey.RANKING, item.getSec_openid());
            if (rank == null) {
                item.setWorldRank(9999999);
            } else {
                item.setWorldRank(Math.toIntExact(rank + 1));
            }
            Double allscore = redisTemplate.opsForZSet().score(RedisCacheKey.RANKING, item.getSec_openid());
            if (allscore != null) {
                item.setAllscore(allscore.longValue());
            }
            // 更新缓存
            redisTemplate.opsForHash().put(dataMapKey, item.getSec_openid(), item);
        }

        // 如果列表超过100人，则只返回前100人,只返回胜利玩家的前100人
        if (winList.size() > 100) {
            winList = winList.subList(0, 100);
        }
        for (int i = 0; i < winList.size(); i++) {
            PlayerDataDTO playerDataDTO = winList.get(i);
            playerDataDTO.setRank(i + 1);
        }
        return winList;
    }

    /**
     * 持久化玩家数据
     *
     * @param roomId
     */
    @Override
    public void persistPlayerData(String roomId) {
        String roundId = roundHelper.currentRoundId(roomId);
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);//后端备份的数据
        Constant.roomlist.add(dataMapKey);//房间放入的rediskey用于同步用户数据
//        rocketMQTemplate.asyncSend(MqConstant.PLAYER_DATA_RANK, dataMapKey, new RoomDataSendCallback());
    }

    @Override
    public void getPlayerVariation(String openid, int ballCount, String roomId, String roundId) {
        // 从 Redis 中获取 dataMapKey 对应的 Map
        String dataMapKey = RedisCacheKey.getkey(RedisCacheKey.ROOM_DATA, roomId, roundId);//后端备份的数据
        PlayerDataDTO playerDataDto = (PlayerDataDTO) redisTemplate.opsForHash().get(dataMapKey, openid);

        playerDataDto.setBall(ballCount);
        // 将修改后的 item 存回 Redis

        redisTemplate.opsForHash().put(dataMapKey, openid, playerDataDto);

    }


}
